<?php
// +----------------------------------------------------------------------
// | INPHP
// +----------------------------------------------------------------------
// | Copyright (c) 2021 https://inphp.cc All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( https://opensource.org/licenses/MIT )
// +----------------------------------------------------------------------
// | Author: lulanyin <me@lanyin.lu>
// +----------------------------------------------------------------------
namespace Inphp\Service;

use Inphp\App;
use Inphp\Config;
use Inphp\Util\File;

/**
 * 统一服务
 * Class Service
 * @package Inphp\Service
 */
class Service implements IService
{

    /**
     * @var Server|null
     */
    public Server|null $server = null;

    const WS = 'ws';
    const HTTP = 'http';
    const SWOOLE = 'swoole';
    const FPM = 'fpm';

    /**
     * Service constructor.
     * @param bool $swoole 是否使用 Swoole 启动服务
     * @param bool $ws 是否是启动 websocket 服务，前提是使用 swoole
     */
    public function __construct(bool $swoole = false, bool $ws = false)
    {
        //是否ws服务
        $ws = $swoole && $ws;
        //实例化
        $this->server = $ws ? new Websocket\Server(true)  : new Http\Server($swoole);
        //如果是Swoole服务，打印终端提示
        if($swoole){
            //运行 server 服务，由 Swoole 拓展支持
            echo "+---------------------+\r\n";
            echo "| ♪♪♪♪♪♪ INPHP ♪♪♪♪♪♪ |\r\n";
            echo "| Think you for using |\r\n";
            echo "|  support by swoole  |\r\n";
            echo "|  https://inphp.cc   |\r\n";
            echo "+---------------------+\r\n";
        }
    }

    /**
     * 服务启动
     */
    public function start(): void
    {
        // TODO: Implement start() method.
        $this->server->start();
    }

    /**
     * 检测是否使用Swoole服务
     * @return bool
     */
    public static function isSwoole() : bool {
        return App::isSwoole();
    }


    /**
     * 热更新
     * @param string $type
     * @param $callback
     */
    public static function hotUpdate(string $type, $callback = null) : void
    {
        $config = Config::get('service.'.($type == self::WS ? self::WS : self::HTTP));
        $hot_update = $config['hot_update'];
        $version = $hot_update['version_file'];
        $dirs = $hot_update['listen_dir'] ?? [];
        if(empty($dirs)){
            return;
        }
        $files = [];
        $view_suffix = $config['view_suffix'] ?? 'html';
        foreach ($dirs as $dir){
            $files = array_merge($files, File::getAllFiles($dir, "php|{$view_suffix}|json"));
        }
        $list = [];
        foreach ($files as $item){
            $list[] = [
                "md5" => $item['md5'],
                "file"=> $item['path']
            ];
        }
        if(is_file($version)){
            $md5_old = md5_file($version);
            $md5_new = md5(json_encode($list, JSON_UNESCAPED_UNICODE));
            if($md5_old != $md5_new){
                echo date("Y/m/d H:i:s")." server restart ...\r\n";
                //apc_clear_cache();
                if(function_exists('opcache_reset')){
                    @opcache_reset();
                }
                @file_put_contents($version, json_encode($list, JSON_UNESCAPED_UNICODE));
                if($callback instanceof \Closure){
                    $callback();
                }
                echo date("Y/m/d H:i:s").' 完成热更新...'.PHP_EOL;
            }
        }else{
            @file_put_contents($version, json_encode($list, JSON_UNESCAPED_UNICODE));
        }
    }

    /**
     * 统一处理中间键
     * @param array $middleware_list        中间键function列表
     * @param array $call_user_func_args    参数
     */
    public static function processMiddlewares(array $middleware_list = [], array $call_user_func_args = []) : void
    {
        foreach ($middleware_list as $middleware){
            if(is_array($middleware)){
                //[__class__, 'static method']
                $_class = $middleware[0];
                $_method = $middleware[1] ?? null;
                if(class_exists($_class) && !empty($_method)){
                    call_user_func_array([$_class, $_method], $call_user_func_args);
                }
            }elseif($middleware instanceof \Closure){
                call_user_func_array($middleware, $call_user_func_args);
            }
        }
    }
}